home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / src / linux-headers-2.6.28-15 / arch / s390 / include / asm / rwsem.h < prev    next >
Encoding:
C/C++ Source or Header  |  2008-12-24  |  8.9 KB  |  388 lines

  1. #ifndef _S390_RWSEM_H
  2. #define _S390_RWSEM_H
  3.  
  4. /*
  5.  *  include/asm-s390/rwsem.h
  6.  *
  7.  *  S390 version
  8.  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
  9.  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
  10.  *
  11.  *  Based on asm-alpha/semaphore.h and asm-i386/rwsem.h
  12.  */
  13.  
  14. /*
  15.  *
  16.  * The MSW of the count is the negated number of active writers and waiting
  17.  * lockers, and the LSW is the total number of active locks
  18.  *
  19.  * The lock count is initialized to 0 (no active and no waiting lockers).
  20.  *
  21.  * When a writer subtracts WRITE_BIAS, it'll get 0xffff0001 for the case of an
  22.  * uncontended lock. This can be determined because XADD returns the old value.
  23.  * Readers increment by 1 and see a positive value when uncontended, negative
  24.  * if there are writers (and maybe) readers waiting (in which case it goes to
  25.  * sleep).
  26.  *
  27.  * The value of WAITING_BIAS supports up to 32766 waiting processes. This can
  28.  * be extended to 65534 by manually checking the whole MSW rather than relying
  29.  * on the S flag.
  30.  *
  31.  * The value of ACTIVE_BIAS supports up to 65535 active processes.
  32.  *
  33.  * This should be totally fair - if anything is waiting, a process that wants a
  34.  * lock will go to the back of the queue. When the currently active lock is
  35.  * released, if there's a writer at the front of the queue, then that and only
  36.  * that will be woken up; if there's a bunch of consequtive readers at the
  37.  * front, then they'll all be woken up, but no other readers will be.
  38.  */
  39.  
  40. #ifndef _LINUX_RWSEM_H
  41. #error "please don't include asm/rwsem.h directly, use linux/rwsem.h instead"
  42. #endif
  43.  
  44. #ifdef __KERNEL__
  45.  
  46. #include <linux/list.h>
  47. #include <linux/spinlock.h>
  48.  
  49. struct rwsem_waiter;
  50.  
  51. extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *);
  52. extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *);
  53. extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *);
  54. extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *);
  55. extern struct rw_semaphore *rwsem_downgrade_write(struct rw_semaphore *);
  56.  
  57. /*
  58.  * the semaphore definition
  59.  */
  60. struct rw_semaphore {
  61.     signed long        count;
  62.     spinlock_t        wait_lock;
  63.     struct list_head    wait_list;
  64. #ifdef CONFIG_DEBUG_LOCK_ALLOC
  65.     struct lockdep_map    dep_map;
  66. #endif
  67. };
  68.  
  69. #ifndef __s390x__
  70. #define RWSEM_UNLOCKED_VALUE    0x00000000
  71. #define RWSEM_ACTIVE_BIAS    0x00000001
  72. #define RWSEM_ACTIVE_MASK    0x0000ffff
  73. #define RWSEM_WAITING_BIAS    (-0x00010000)
  74. #else /* __s390x__ */
  75. #define RWSEM_UNLOCKED_VALUE    0x0000000000000000L
  76. #define RWSEM_ACTIVE_BIAS    0x0000000000000001L
  77. #define RWSEM_ACTIVE_MASK    0x00000000ffffffffL
  78. #define RWSEM_WAITING_BIAS    (-0x0000000100000000L)
  79. #endif /* __s390x__ */
  80. #define RWSEM_ACTIVE_READ_BIAS    RWSEM_ACTIVE_BIAS
  81. #define RWSEM_ACTIVE_WRITE_BIAS    (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
  82.  
  83. /*
  84.  * initialisation
  85.  */
  86.  
  87. #ifdef CONFIG_DEBUG_LOCK_ALLOC
  88. # define __RWSEM_DEP_MAP_INIT(lockname) , .dep_map = { .name = #lockname }
  89. #else
  90. # define __RWSEM_DEP_MAP_INIT(lockname)
  91. #endif
  92.  
  93. #define __RWSEM_INITIALIZER(name) \
  94.  { RWSEM_UNLOCKED_VALUE, __SPIN_LOCK_UNLOCKED((name).wait.lock), \
  95.    LIST_HEAD_INIT((name).wait_list) __RWSEM_DEP_MAP_INIT(name) }
  96.  
  97. #define DECLARE_RWSEM(name) \
  98.     struct rw_semaphore name = __RWSEM_INITIALIZER(name)
  99.  
  100. static inline void init_rwsem(struct rw_semaphore *sem)
  101. {
  102.     sem->count = RWSEM_UNLOCKED_VALUE;
  103.     spin_lock_init(&sem->wait_lock);
  104.     INIT_LIST_HEAD(&sem->wait_list);
  105. }
  106.  
  107. extern void __init_rwsem(struct rw_semaphore *sem, const char *name,
  108.              struct lock_class_key *key);
  109.  
  110. #define init_rwsem(sem)                \
  111. do {                        \
  112.     static struct lock_class_key __key;    \
  113.                         \
  114.     __init_rwsem((sem), #sem, &__key);    \
  115. } while (0)
  116.  
  117.  
  118. /*
  119.  * lock for reading
  120.  */
  121. static inline void __down_read(struct rw_semaphore *sem)
  122. {
  123.     signed long old, new;
  124.  
  125.     asm volatile(
  126. #ifndef __s390x__
  127.         "    l    %0,0(%3)\n"
  128.         "0:    lr    %1,%0\n"
  129.         "    ahi    %1,%5\n"
  130.         "    cs    %0,%1,0(%3)\n"
  131.         "    jl    0b"
  132. #else /* __s390x__ */
  133.         "    lg    %0,0(%3)\n"
  134.         "0:    lgr    %1,%0\n"
  135.         "    aghi    %1,%5\n"
  136.         "    csg    %0,%1,0(%3)\n"
  137.         "    jl    0b"
  138. #endif /* __s390x__ */
  139.         : "=&d" (old), "=&d" (new), "=m" (sem->count)
  140.         : "a" (&sem->count), "m" (sem->count),
  141.           "i" (RWSEM_ACTIVE_READ_BIAS) : "cc", "memory");
  142.     if (old < 0)
  143.         rwsem_down_read_failed(sem);
  144. }
  145.  
  146. /*
  147.  * trylock for reading -- returns 1 if successful, 0 if contention
  148.  */
  149. static inline int __down_read_trylock(struct rw_semaphore *sem)
  150. {
  151.     signed long old, new;
  152.  
  153.     asm volatile(
  154. #ifndef __s390x__
  155.         "    l    %0,0(%3)\n"
  156.         "0:    ltr    %1,%0\n"
  157.         "    jm    1f\n"
  158.         "    ahi    %1,%5\n"
  159.         "    cs    %0,%1,0(%3)\n"
  160.         "    jl    0b\n"
  161.         "1:"
  162. #else /* __s390x__ */
  163.         "    lg    %0,0(%3)\n"
  164.         "0:    ltgr    %1,%0\n"
  165.         "    jm    1f\n"
  166.         "    aghi    %1,%5\n"
  167.         "    csg    %0,%1,0(%3)\n"
  168.         "    jl    0b\n"
  169.         "1:"
  170. #endif /* __s390x__ */
  171.         : "=&d" (old), "=&d" (new), "=m" (sem->count)
  172.         : "a" (&sem->count), "m" (sem->count),
  173.           "i" (RWSEM_ACTIVE_READ_BIAS) : "cc", "memory");
  174.     return old >= 0 ? 1 : 0;
  175. }
  176.  
  177. /*
  178.  * lock for writing
  179.  */
  180. static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
  181. {
  182.     signed long old, new, tmp;
  183.  
  184.     tmp = RWSEM_ACTIVE_WRITE_BIAS;
  185.     asm volatile(
  186. #ifndef __s390x__
  187.         "    l    %0,0(%3)\n"
  188.         "0:    lr    %1,%0\n"
  189.         "    a    %1,%5\n"
  190.         "    cs    %0,%1,0(%3)\n"
  191.         "    jl    0b"
  192. #else /* __s390x__ */
  193.         "    lg    %0,0(%3)\n"
  194.         "0:    lgr    %1,%0\n"
  195.         "    ag    %1,%5\n"
  196.         "    csg    %0,%1,0(%3)\n"
  197.         "    jl    0b"
  198. #endif /* __s390x__ */
  199.         : "=&d" (old), "=&d" (new), "=m" (sem->count)
  200.         : "a" (&sem->count), "m" (sem->count), "m" (tmp)
  201.         : "cc", "memory");
  202.     if (old != 0)
  203.         rwsem_down_write_failed(sem);
  204. }
  205.  
  206. static inline void __down_write(struct rw_semaphore *sem)
  207. {
  208.     __down_write_nested(sem, 0);
  209. }
  210.  
  211. /*
  212.  * trylock for writing -- returns 1 if successful, 0 if contention
  213.  */
  214. static inline int __down_write_trylock(struct rw_semaphore *sem)
  215. {
  216.     signed long old;
  217.  
  218.     asm volatile(
  219. #ifndef __s390x__
  220.         "    l    %0,0(%2)\n"
  221.         "0:    ltr    %0,%0\n"
  222.         "    jnz    1f\n"
  223.         "    cs    %0,%4,0(%2)\n"
  224.         "    jl    0b\n"
  225. #else /* __s390x__ */
  226.         "    lg    %0,0(%2)\n"
  227.         "0:    ltgr    %0,%0\n"
  228.         "    jnz    1f\n"
  229.         "    csg    %0,%4,0(%2)\n"
  230.         "    jl    0b\n"
  231. #endif /* __s390x__ */
  232.         "1:"
  233.         : "=&d" (old), "=m" (sem->count)
  234.         : "a" (&sem->count), "m" (sem->count),
  235.           "d" (RWSEM_ACTIVE_WRITE_BIAS) : "cc", "memory");
  236.     return (old == RWSEM_UNLOCKED_VALUE) ? 1 : 0;
  237. }
  238.  
  239. /*
  240.  * unlock after reading
  241.  */
  242. static inline void __up_read(struct rw_semaphore *sem)
  243. {
  244.     signed long old, new;
  245.  
  246.     asm volatile(
  247. #ifndef __s390x__
  248.         "    l    %0,0(%3)\n"
  249.         "0:    lr    %1,%0\n"
  250.         "    ahi    %1,%5\n"
  251.         "    cs    %0,%1,0(%3)\n"
  252.         "    jl    0b"
  253. #else /* __s390x__ */
  254.         "    lg    %0,0(%3)\n"
  255.         "0:    lgr    %1,%0\n"
  256.         "    aghi    %1,%5\n"
  257.         "    csg    %0,%1,0(%3)\n"
  258.         "    jl    0b"
  259. #endif /* __s390x__ */
  260.         : "=&d" (old), "=&d" (new), "=m" (sem->count)
  261.         : "a" (&sem->count), "m" (sem->count),
  262.           "i" (-RWSEM_ACTIVE_READ_BIAS)
  263.         : "cc", "memory");
  264.     if (new < 0)
  265.         if ((new & RWSEM_ACTIVE_MASK) == 0)
  266.             rwsem_wake(sem);
  267. }
  268.  
  269. /*
  270.  * unlock after writing
  271.  */
  272. static inline void __up_write(struct rw_semaphore *sem)
  273. {
  274.     signed long old, new, tmp;
  275.  
  276.     tmp = -RWSEM_ACTIVE_WRITE_BIAS;
  277.     asm volatile(
  278. #ifndef __s390x__
  279.         "    l    %0,0(%3)\n"
  280.         "0:    lr    %1,%0\n"
  281.         "    a    %1,%5\n"
  282.         "    cs    %0,%1,0(%3)\n"
  283.         "    jl    0b"
  284. #else /* __s390x__ */
  285.         "    lg    %0,0(%3)\n"
  286.         "0:    lgr    %1,%0\n"
  287.         "    ag    %1,%5\n"
  288.         "    csg    %0,%1,0(%3)\n"
  289.         "    jl    0b"
  290. #endif /* __s390x__ */
  291.         : "=&d" (old), "=&d" (new), "=m" (sem->count)
  292.         : "a" (&sem->count), "m" (sem->count), "m" (tmp)
  293.         : "cc", "memory");
  294.     if (new < 0)
  295.         if ((new & RWSEM_ACTIVE_MASK) == 0)
  296.             rwsem_wake(sem);
  297. }
  298.  
  299. /*
  300.  * downgrade write lock to read lock
  301.  */
  302. static inline void __downgrade_write(struct rw_semaphore *sem)
  303. {
  304.     signed long old, new, tmp;
  305.  
  306.     tmp = -RWSEM_WAITING_BIAS;
  307.     asm volatile(
  308. #ifndef __s390x__
  309.         "    l    %0,0(%3)\n"
  310.         "0:    lr    %1,%0\n"
  311.         "    a    %1,%5\n"
  312.         "    cs    %0,%1,0(%3)\n"
  313.         "    jl    0b"
  314. #else /* __s390x__ */
  315.         "    lg    %0,0(%3)\n"
  316.         "0:    lgr    %1,%0\n"
  317.         "    ag    %1,%5\n"
  318.         "    csg    %0,%1,0(%3)\n"
  319.         "    jl    0b"
  320. #endif /* __s390x__ */
  321.         : "=&d" (old), "=&d" (new), "=m" (sem->count)
  322.         : "a" (&sem->count), "m" (sem->count), "m" (tmp)
  323.         : "cc", "memory");
  324.     if (new > 1)
  325.         rwsem_downgrade_wake(sem);
  326. }
  327.  
  328. /*
  329.  * implement atomic add functionality
  330.  */
  331. static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem)
  332. {
  333.     signed long old, new;
  334.  
  335.     asm volatile(
  336. #ifndef __s390x__
  337.         "    l    %0,0(%3)\n"
  338.         "0:    lr    %1,%0\n"
  339.         "    ar    %1,%5\n"
  340.         "    cs    %0,%1,0(%3)\n"
  341.         "    jl    0b"
  342. #else /* __s390x__ */
  343.         "    lg    %0,0(%3)\n"
  344.         "0:    lgr    %1,%0\n"
  345.         "    agr    %1,%5\n"
  346.         "    csg    %0,%1,0(%3)\n"
  347.         "    jl    0b"
  348. #endif /* __s390x__ */
  349.         : "=&d" (old), "=&d" (new), "=m" (sem->count)
  350.         : "a" (&sem->count), "m" (sem->count), "d" (delta)
  351.         : "cc", "memory");
  352. }
  353.  
  354. /*
  355.  * implement exchange and add functionality
  356.  */
  357. static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem)
  358. {
  359.     signed long old, new;
  360.  
  361.     asm volatile(
  362. #ifndef __s390x__
  363.         "    l    %0,0(%3)\n"
  364.         "0:    lr    %1,%0\n"
  365.         "    ar    %1,%5\n"
  366.         "    cs    %0,%1,0(%3)\n"
  367.         "    jl    0b"
  368. #else /* __s390x__ */
  369.         "    lg    %0,0(%3)\n"
  370.         "0:    lgr    %1,%0\n"
  371.         "    agr    %1,%5\n"
  372.         "    csg    %0,%1,0(%3)\n"
  373.         "    jl    0b"
  374. #endif /* __s390x__ */
  375.         : "=&d" (old), "=&d" (new), "=m" (sem->count)
  376.         : "a" (&sem->count), "m" (sem->count), "d" (delta)
  377.         : "cc", "memory");
  378.     return new;
  379. }
  380.  
  381. static inline int rwsem_is_locked(struct rw_semaphore *sem)
  382. {
  383.     return (sem->count != 0);
  384. }
  385.  
  386. #endif /* __KERNEL__ */
  387. #endif /* _S390_RWSEM_H */
  388.